package com.frontalcode 
{
	import flash.utils.*;
	
	/**
	 * The ContainerManager class handles the <manager /> tag.
	 */
    public class ContainerManager extends DocumentElement
    {
		// XXX This should be a getter.
		//
		/**
		 * Is the manager paused?
		 */
		public var paused : Boolean = false;
		
		/**
		 * @private
		 */
		internal var transitioners : Array = [ ];

		/**
		 * @private
		 */
		internal var holdTaskId : uint = 0;

		/**
		 * @private
		 */
		internal var progressTaskId : uint = 0;

		/**
		 * @private
		 */
		internal var transitionFrames : uint;
		
		private var _containerHierarchy : Dictionary;
		private var _current : Container = null;
		private var _next : Container = null;
		private var _afterNext : Container = null;
		private var _autoPlay : Boolean = false;
		
		// jumpTo is not re-entrant.
		//
		private var jumpWhileInProgress : Object = null;
		private var jumpInProgress : Boolean = false;
		
		/**
		 * Creates a new ContainerManager instance.
		 * 
		 * <p>Options may be set through the constructor, the movie's URL or the
		 * movie's FlashVars parameter. The following options are supported:
		 * 	<table class="innertable">
		 * 		<tr><th>Option</th><th>Default</th><th>Description</th></tr>
		 * 		<tr><td>filterJumpRequests</td><td>true</td><td>If true (the default) then we ignore jumps to containers that we are already in the process of jumping to.</td></tr>
		 * 	</table>
		 * </p>  
		 *
		 * @param document	The document this element belongs to.
		 * @param parent	The element's parent in the document tree.
		 * @param node		The XML node this element is associated with.
		 * @param options	Options affecting the behavior of this instance.
		 * 					(This object does not have built-in support for any
		 * 					options.)
		 */
		public function ContainerManager ( document : Document, parent : DocumentElement, node : XML, options : Object = null )
		{
			super ( document, parent, node, options );
			
			setObjectOptionDefault ( "filterJumpRequests", true );
			setOptionsFromLoaderParameters ( );			
		}
		
		/**
		 * getContainerByIndex is called on our parent element.
		 */
		override public function getContainerByIndex ( index : *, stopAtChildren : Boolean = true, showWarnings : Boolean = true ) : Container { return parent.getContainerByIndex ( index, stopAtChildren, showWarnings ); }
		
		/**
		 * @private
		 */
		override public function applyInteractions ( ) : void
		{
			super.applyInteractions ( );
			
			if ( ! attributesHaveChanges ) return; 

			// Now add listeners for any interactions tied to our events.
			//
			applyInteraction ( ContainerMgrEvent.WILL_SELECT );
			applyInteraction ( ContainerMgrEvent.SELECT );
			applyInteraction ( ContainerMgrEvent.PROGRESS );
			applyInteraction ( ContainerMgrEvent.TRANSITION_END );
			applyInteraction ( ContainerMgrEvent.PAUSE );
			applyInteraction ( ContainerMgrEvent.RESUME );
			applyInteraction ( ContainerMgrEvent.HOLD_PROGRESS );
		}
		
		/**
		 * @private
		 */
		override public function applyStyles ( ) : void
		{
			if ( getStyle ( "wants-reset" ) == null ) setStyle ( "wants-reset", true );
			
			super.applyStyles ( );
			
			if ( getStyle ( "hide-unselected" ) )
			{
				var containers : Array = parent.manageableContainers;
				for ( var i : int = containers.length - 1; i >= 0; i-- ) 
				{
					if ( current !== containers [ i ] && next !== containers [ i ] && ( current != null || next != null || getInitial ( ) !== containers [ i ] ) ) 
					{
						containers [ i ].setStyle ( "display", "none" );
					}
				}
			}
		}
		
		/**
		 * The Container elements that are managed by this manager.
		 */
		public function get managedContainers ( ) : Array { return parent.manageableContainers; }
		
		/*
			Function: reset
		*/
		/**
		 * @private
		 */
		override public function reset ( ) : void
		{
			var isInitialReset : Boolean = this.isInitialReset;
			
			super.reset ( );
			
			var initialContainer : Container = getInitial ( );
			var containers : Array = parent.manageableContainers;

			var isDeepLink : Boolean = false;
			if ( isInitialReset ) 
			{
				var deepLinkValue : * = checkForDeepLink ( );
				if ( deepLinkValue != null ) 
				{
					isDeepLink = true;
					initialContainer = deepLinkValue as Container;
				}
			}
			
			for ( var i : int = containers.length - 1; i >= 0; i-- ) 
			{
				var index : uint = ( initialContainer.childIndex + i ) % containers.length;
				
				// Prepare our assets again if the container we are going to
				// differs from that assumed by prepareAssets ( ).
				//
				if ( getInitial ( ) !== initialContainer ) containers [ index ].prepareAssets ( );
				
				if ( containers [ index ] !== initialContainer && getStyle ( "hide-unselected" ) ) containers [ index ].setStyle ( "display", "none" );
			}
			
			// If this is our initial reset and hide-unselected is true then our
			// initial container has not been rendered yet and so it has not yet
			// applied its interaction listeners like onSelect. This is a
			// problem if we jump now and then render.
			//
			
			if ( parent != null && containers.length > 0 ) jumpTo ( initialContainer, getStyle ( "initial-jump-is-quick" ) );
			
			// XXX This is pretty ugly. We're basically replicating 
			// processDeepLink in this function. So to complete the replication, 
			// we call the super here.
			//
			if ( isDeepLink ) super.processDeepLink ( deepLinkValue );
		}
		
		override public function prepareAssets ( ) : void
		{
			var containers : Array = parent.manageableContainers;
			for ( var i : int = containers.length - 1; i >= 0; i-- ) 
			{
				var index : uint = ( getInitial ( ).childIndex + i ) % containers.length;
				
				// We prepare all of our children's assets (which moves them up 
				// in the pending queue). In addition, selecting a child will
				// likely cause it to be reset and so bring its assets to the
				// top of the queue again. The scenario of concern is a container
				// without multiple slide shows, say. We want all the assets
				// higher in the queue than other system assets but we want the
				// topmost slides at the very top of the queue.
				//
				containers [ index ].prepareAssets ( );
			}
		}
		
		/*
			Function: containerHierarchy
			
				This function analyzes our parent's containers and their
				parentElemNdx attributes to define a container hierarchy. We use
				this hierarchy then to set the parentSelected, childSelected and
				siblingSelected pseudoclasses.
		*/
		/**
		 * @private
		 */
		internal function get containerHierarchy ( ) : Dictionary
		{
			if ( _containerHierarchy != null ) return _containerHierarchy;
			_containerHierarchy = new Dictionary ( true );
			
			for ( var i : uint = 0; i < parent.manageableContainers.length; i++ )
			{
				_containerHierarchy [ parent.manageableContainers [ i ] ] = { children: [ ], parents: [ ] };
			}
			
			// And we use the ContainerManager as a root entry though it will
			// never have any pseudoclasses set on it.
			//
			_containerHierarchy [ this ] = { children: [ ], parents: [ ] };
			
			for ( i = 0; i < parent.manageableContainers.length; i++ )
			{
				var container : Container = parent.manageableContainers [ i ];
				
				// XXX How to support multiple parents?
				//
				var hierParent : DocumentElement = container.node.@parentElemNdx == undefined ? this : getContainerByIndex ( container.node.@parentElemNdx );
				_containerHierarchy [ hierParent ].children.push ( container );
				_containerHierarchy [ container ].parents.push ( hierParent );
			}
			
			return _containerHierarchy;
		}
		
		/*
			Function: markHierarchy
			
				When a managed Container becomes selected, this affects the
				hierarchical pseudoclasses for it and other Containers sharing a
				common ContainerManager. Here we scan the hierachy created by
				<buildHierarchy> setting these pseudoclasses based on each
				Container's relationship to the selected Container.
				
				If a Container is the parent of the selected Container then its
				pseudoclass childSelected is set to 1. If it is the grandparent
				then it is set to 2 and so on. If the Container is not a parent
				at any level then childSelected is set to 0.
				
				If a Container is a sibling of a Container that has a child
				selected at any level, then its pseudoclass nephewSelected is
				set to the same value that sibling's childSelected pseudoclass.
				
				If a Container is a sibling of the selected Container then its
				pseudoclass siblingSelected is set to true otherwise it is 
				false. (A Container is not its own sibling.)
				
				If a Container is a child of the selected Container then its
				pseudoclass parentSelected is set to 1. If it is a grandchild
				then parentSelected is set to 2 and so on. If the Container is
				not a child at any level then parentSelected is set to 0.
				
				With these pseudoclasses, we can create fairly complex menu
				behaviors.
			
			Parameters:
			
				selected	- The selected Container.
		*/
		/**
		 * @private
		 */
		internal function markHierarchy ( selected : Container ) : void
		{
			// We markup the Container hierarchy first using temporary
			// variables. This is so that we know the final values before we
			// set them on the Containers. And this is so the we do not send
			// any unneeded PSEUDO_CLASS_STATE_CHANGE events.
			//
			// First, we clear the hierarchy.
			//
			for ( var i : uint = 0; i < parent.manageableContainers.length; i++ )
			{
				var entry: Object = containerHierarchy [ parent.manageableContainers [ i ] ];
				entry.nephewSelected = 0;
				entry.childSelected = 0;
				entry.parentSelected = 0;
				entry.siblingSelected = false;
			}
			
			// Now markup the hierarchy into our temporary variables.
			//
			if ( selected != null )
			{
				markSiblingsInHierarchy ( selected, "siblingSelected", true );
				markDescendantsInHierarchy ( selected, 1 );
				markAncestorsInHierarchy ( selected, 1 );
			}
			
			// Now transfer the temporary variables to the Containers.
			//
			for ( i = 0; i < parent.manageableContainers.length; i++ )
			{
				entry = containerHierarchy [ parent.manageableContainers [ i ] ];
				parent.manageableContainers [ i ].setPseudoClassState ( "nephewSelected", entry.nephewSelected );
				parent.manageableContainers [ i ].setPseudoClassState ( "childSelected", entry.childSelected );
				parent.manageableContainers [ i ].setPseudoClassState ( "parentSelected", entry.parentSelected );
				parent.manageableContainers [ i ].setPseudoClassState ( "siblingSelected", entry.siblingSelected );
			}
		}
		
		/**
		 * @private
		 */
		internal function markSiblingsInHierarchy ( container : Container, property : String, value : * ) : void
		{
			var parents : Array = containerHierarchy [ container ].parents;
			for ( var i : uint = 0; i < parents.length; i++ )
			{
				var siblings : Array = containerHierarchy [ parents [ i ] ].children;
				for ( var j : uint = 0; j < siblings.length; j++ )
				{
					if ( siblings [ j ] !== container ) containerHierarchy [ siblings [ j ] ] [ property ] = value;
				}
			}
		}
		
		/**
		 * @private
		 */
		internal function markDescendantsInHierarchy ( container : Container, level : uint ) : void
		{
			var children : Array = containerHierarchy [ container ].children;
			for ( var i : uint = 0; i < children.length; i++ )
			{
				containerHierarchy [ children [ i ] ].parentSelected = level;
				markDescendantsInHierarchy ( children [ i ], level + 1 );
			}
		}
		
		/**
		 * @private
		 */
		internal function markAncestorsInHierarchy ( container : Container, level : uint ) : void
		{
			var parents : Array = containerHierarchy [ container ].parents;
			for ( var i : uint = 0; i < parents.length; i++ )
			{
				if ( parents [ i ] === this ) continue;
				containerHierarchy [ parents [ i ] ].childSelected = level;
				markSiblingsInHierarchy ( parents [ i ], "nephewSelected", level );
				markAncestorsInHierarchy ( parents [ i ], level + 1 );
			}
		}
		
		/**
		 * Get the hierarchical name of the managed element.
		 *
		 * As this value is most likely to be used for deep linking, we support
		 * and option to do URL escaping. We do this minimally though in order
		 * to make the value as readable as possible. We replace question marks
		 * and slashes with the appropriate escapes.
		 */
		public function getHierarchicalChildName ( container : Container, urlEscape : Boolean = true ) : String
		{
			var result : String = container.node.@name != undefined ? container.node.@name : String ( container.childIndex + 1 );
			if ( urlEscape )
			{
				result = result.replace ( "?", "%3F" );
				result = result.replace ( "/", "%2F" );
			}
			
			var scan : DocumentElement = containerHierarchy [ container ].parents.length > 0 ? containerHierarchy [ container ].parents [ 0 ] : null;
			while ( scan !== this && scan != null )
			{
				var entry : String = scan.node.@name != undefined ? scan.node.@name : String ( ( scan as Container ).childIndex + 1 );
				if ( urlEscape )
				{
					entry = entry.replace ( "?", "%3F" );
					entry = entry.replace ( "/", "%2F" );
				}
				result = entry + "/" + result;
				scan = containerHierarchy [ scan ].parents.length > 0 ? containerHierarchy [ scan ].parents [ 0 ] : null;
			}
			
			return "/" + result;
		}
		
		/**
		 * Jump to the given index.
		 *
		 * @param index		A Container element or an index to pass to 
		 * 					getContainerByIndex to determine the element to
		 *					transition to.
		 * @param quick		If true then transitioners will be cut short and
		 * 					the indexed element made the current element.
		 */
		public function jumpTo ( index : *, quick : Boolean = false ) : void
		{
			if ( jumpInProgress )
			{
				jumpWhileInProgress = { index: index, quick: quick };
				return;
			}
			
			try
			{
				jumpInProgress = true;
				jumpWhileInProgress = null;
				
				// XXX We allow jumps to the current and next container. Will this
				// cause any issues?
				//
				
				var container : Container;
				
				if ( index is Container ) 
				{
					container = index as Container;
				}
				else
				{
					container = getContainerByIndex ( index );
					if ( container == null ) return;
				}

				if ( getObjectOption ( "filterJumpRequests" ) && ! quick )
				{
					if ( next == null )
					{
						if ( container == current ) return;
					}
					else
					{
						if ( container == next || container == afterNext ) return;
					}
				}
				
				if ( holdTaskId != 0 )
				{
					dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.HOLD_PROGRESS, this, 1 ) );
					holdTaskId = Scheduler.getInstance ( ).removeTask ( holdTaskId );
				}
				
				if ( next != null )
				{
					if ( quick ) 
					{
						// The last fforward will call transitionDone which will
						// set the current and next properties.
						//
						for ( var i : uint = 0; i < transitioners.length; i++ ) transitioners [ i ].t.fforward ( );
						dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.PROGRESS, this, 1 ) );
						if ( current == container ) return;
					}
					else
					{
						afterNext = container;
						return;
					}
				}
				
				transitioners = [ ];
				
				for ( i = 0; i < elements.length; i++ )
				{
					if ( elements [ i ].willHandleJump ( current, container ) ) 
					{
						transitioners.push ( { t: elements [ i ], done: false } );
					}
				}
				
				if ( getStyle ( "hide-unselected" ) ) container.setStyle ( "display", "block" );
				next = container;
				
				dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.PROGRESS, this, 0 ) );
				
				if ( transitioners.length == 0 )
				{
					// This is an annoying warning.
					//
					// if ( elements.length > 0 ) Debugger.logMessage ( Debugger.WARNING, "Manager", "cannot find any transitioners to go from container " + ( current != null ? current.childIndex : "null" ) + " to " + next.childIndex );
					transitionDone ( null );
				}
				else
				{
					transitionFrames = 0;
					progressTaskId = Scheduler.getInstance ( ).scheduleTask ( progressTaskId, dispatchProgress );
					
					for ( i = 0; i < transitioners.length; i++ ) 
					{
						transitioners [ i ].t.start ( );
						if ( quick ) transitioners [ i ].t.fforward ( );
					}
				}
			}
			finally
			{
				jumpInProgress = false;
				if ( jumpWhileInProgress != null ) jumpTo ( jumpWhileInProgress.index, jumpWhileInProgress.quick );
			}
		}
		
		/**
		 * @private
		 */
		public function transitionDone ( transitioner : Transitioner ) : void
		{
			var allDone : Boolean = true;
			
			for ( var i : uint = 0; i < transitioners.length; i++ )
			{
				if ( transitioners [ i ].t === transitioner ) 
				{
					transitioners [ i ].done = true;
				}
				else if ( ! transitioners [ i ].done )
				{
					allDone = false;
				}
			}
			
			if ( allDone )
			{
				// Set chained to true on all transitioners except for the one
				// that completes last on its target. This is because 
				// transitionDone will hide the target is "hide-unselected" is
				// true and it's called by the last transitioner.
				//
				if ( current != null && current != next && getStyle ( "hide-unselected" ) ) current.setStyle ( "display", "none" );
				
				progressTaskId = Scheduler.getInstance ( ).removeTask ( progressTaskId );
				dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.PROGRESS, this, 1 ) );
				current = next;
				next = null;
			}
		}
		
		/**
		 * @private
		 */
		public function dispatchProgress ( ) : void
		{
			transitionFrames++;
			
			var maxDuration : Number = 0;
			for ( var i : uint = 0; i < transitioners.length; i++ ) maxDuration = Math.max ( maxDuration, transitioners [ i ].t.duration );
			
			var progress : Number = transitionFrames / maxDuration;
			if ( progress >= 1 ) progress = 1;
			dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.PROGRESS, this, progress ) );
		}
		
		public function set current ( value : Container ) : void
		{
			dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.TRANSITION_END, this ) );
			if ( _current != null && value !== _current )
			{
				_current.selected = false;
				if ( value != null ) value.selected = true;
				markHierarchy ( value );
			}
			_current = value;
		}
		
		public function get current ( ) : Container { return _current; }
		
		public function set next ( value : Container ) : void
		{
			_next = value;
			if ( value != null ) 
			{
				if ( _current != null ) _current.selected = false;
				value.selected = true;
				markHierarchy ( value );
				
				// Now apply the temporary variables to the containers'
				// pseudoclasses.
				//
				dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.SELECT, this ) );
				
				if ( getStyle ( "deep-link" ) == "path"  ) DeepLinkManager.updateDeepLink ( this, getDeepLinkIndex ( value ), value.node.@name != undefined ? value.node.@name : null );				
				if ( getStyle ( "deep-link" ) == "query" ) DeepLinkManager.updateDeepLink ( this, getDeepLinkIndex ( value ), null );				
			}
			
			if ( next == null )
			{
				if ( afterNext != null ) 
				{
					var container : Container = afterNext;
					afterNext = null;
					jumpTo ( container );
				}
				else if ( getStyle ( "auto-play" ) )
				{
					holdTaskId = Scheduler.getInstance ( ).scheduleTask ( holdTaskId, hold, null, 0, getStyle ( "hold-time" ), null, null, false, getStyle ( "hold-time-use-secs" ) === true ? false : true, false, getStyle ( "hold-time-use-secs" ) === true ? false : true );
					if ( paused ) Scheduler.getInstance ( ).pauseTask ( holdTaskId );
				}
			}
		}
		
		/**
		 * @private
		 */
		public function hold ( taskId : uint, runningForXSecs : Number, endInXSecs : Number ) : void
		{
			var progress : Number = runningForXSecs + endInXSecs == 0 ? 1 : runningForXSecs / ( runningForXSecs + endInXSecs );
			if ( progress > 1 ) progress = 1;
			dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.HOLD_PROGRESS, this, progress ) );
			if ( progress >= 1 ) 
			{
				var next : Container = getNext ( 1, ! getStyle ( "stop-at-end" ) );
				if ( next != null ) jumpTo ( next );
			}
		}
		
		/**
		 * The initial element for this manager.
		 */
		public function getInitial ( ) : Container
		{
			if ( parent == null || parent.manageableContainers.length == 0 ) return null;
			
			var initialIndex : String = "1";
			if ( ! Util.isEmpty.test ( getAttribute ( "initialIndex" ) ) ) initialIndex = getAttribute ( "initialIndex" );
			
			return getContainerByIndex ( initialIndex );
		}
		
		/*
			Function: getNext
			
				Return the managed container that is delta away from the current
				container. 
				
			Paramters:
			
				delta		- A positive or negative number. E.g., 1 will return
							  the next container.
				wrap		- Whether to wrap around the beginning and end of
							  list of children when applying the delta. If
							  false and the delta extends past the end of the
							  children list then null is returned.
				from		- If set, then do the calculation from this 
							  container.
							  
			Returns:
			
				The next container or null of the children list is empty or if
				wrap is false and the delta is out of the range of the children
				indexes.
		*/
		public function getNext ( delta : int = 1, wrap : Boolean = false, from : Container = null ) : Container
		{
			if ( parent == null || parent.manageableContainers.length == 0 ) return null;
			
			var currentIndex : uint;
			if ( from != null )
			{
				currentIndex = from.childIndex;
			}
			else
			{
				currentIndex = current != null ? current.childIndex : getInitial ( ).childIndex;
			}
			if ( wrap == false && ( currentIndex + delta < 0 || currentIndex + delta >= parent.manageableContainers.length ) ) return null;
			while ( delta < 0 ) delta += parent.manageableContainers.length;
			var nextIndex : uint = ( currentIndex + delta ) % parent.manageableContainers.length;
			return getContainerByIndex ( String ( nextIndex + 1 ) );
		}
		
		public function get next ( ) : Container { return _next; }
		
		public function set afterNext ( value : Container ) : void
		{
			_afterNext = value;
			if ( value != null ) dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.WILL_SELECT, this ) );
		}
		
		public function get afterNext ( ) : Container { return _afterNext; }
		
		override public function addChild ( element : DocumentElement ) : void 
		{ 
			if ( element is Transitioner )
			{
				super.addChild ( element );
			}
			else
			{
				Debugger.logMessage ( Debugger.ERROR, "ContainerManager", "managers may only contain transitioners" );
			}
		}
		
		public function pause ( ) : void
		{
			Scheduler.getInstance ( ).pauseTask ( holdTaskId );
			if ( ! getStyle ( "pause-at-transition-end" ) ) for ( var i : uint = 0; i < transitioners.length; i++ ) transitioners [ i ].t.stop ( );
			if ( ! paused ) dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.PAUSE, this ) );
			paused = true;
		}
		
		public function resume ( ) : void
		{
			Scheduler.getInstance ( ).resumeTask ( holdTaskId );
			if ( ! getStyle ( "pause-at-transition-end" ) ) for ( var i : uint = 0; i < transitioners.length; i++ ) transitioners [ i ].t.resume ( );
			if ( paused ) dispatchEvent ( new ContainerMgrEvent ( ContainerMgrEvent.RESUME, this ) );
			paused = false;
		}
		
		/*
			Function: getDeepLinkValue
			
				Get the Container associated with the deep link index.
			
			Parameters:
			
				index	- The deep link index.
				
			Returns:
			
				The indexed Container.
		*/
		override public function getDeepLinkValue ( index : String ) : *  
		{ 
			var result : * = undefined;
			
			if ( getStyle ( "deep-link" ) == "path" )
			{
				// More than one element may have the same name and so it is not
				// sufficient to strip of the last entry in the path and then to
				// call getContainerByIndex with it. Instead we scan all the
				// elements for one whose hierarchical name matches the index.
				// XXX This seems ripe for optimization but then how often is it
				// called?
				//
				for ( var i : uint = 0; i < parent.containers.length; i++ )
				{
					if ( index == getHierarchicalChildName ( parent.containers [ i ] ) )
					{
						result = parent.containers [ i ];
						break;
					}
				}
			}
			else
			{
				result = getContainerByIndex ( index );
			}
			
			return result;
		}
		
		/*
			Function: getDeepLinkIndex
			
				Get the deep link index associated with the Container.
			
			Parameters:
			
				value	- A Container.
				
			Returns:
			
				The index of the Container.
		*/
		override public function getDeepLinkIndex ( value : * ) : String 
		{ 
			var container : Container = value as Container;
			
			if ( container != null )
			{
				if ( getStyle ( "deep-link" ) == "path" )
				{
					return getHierarchicalChildName ( container );
				}
				else if ( getStyle ( "deep-link" ) == "query" )
				{
					var id : String = String ( container.childIndex + 1 );
					if ( container.node.@name != undefined ) id = container.node.@name;
					if ( container.node.@id != undefined ) id = container.node.@id;
					return id;
				}
			}
			
			return null;
		}
		
		/*
			Function: processDeepLink
			
				Jump to the Container returned by getDeepLinkValue.
			
			Parameters:
			
				value	- The deep linked Container.
		*/
		override public function processDeepLink ( value : * ) : void 
		{ 
			if ( value != null ) jumpTo ( value ); 
			super.processDeepLink ( value );
		}
    }
}

